package com.example.springboot.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.annotation.Configuration;

/**
 * 该接口继承了BeanPostProcess接口
 * <p> BeanPostProcess接口只在bean的初始化阶段进行扩展（注入spring上下文前后），
 * 而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法，把可扩展的范围增加了实例化阶段和属性注入阶段。
 *
 * <p> 这个扩展点非常有用 ，无论是写中间件和业务中，都能利用这个特性。
 * 比如对实现了某一类接口的bean在各个生命期间进行收集，或者对某个类型的bean进行统一的设值等等 。
 *
 * <p>Spring Boot 里很多自动装配功能都是基于这个接口
 * <p>
 *
 * @author Zhang.Z
 * @version 2025-09-21
 * @see Test4SmartInstantiationAwareBeanPostProcessor
 */
@Configuration
public class Test5InstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    /**
     * 实例化bean之前，相当于new这个bean之前
     * <p>构造方法调用前</p>
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if ("car".equals(beanName)) {
            System.out.println("test5 before Instantiation");
        }

        return null;
    }

    /**
     * <p>构造方法调用后，属性填充前</p>
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("car".equals(beanName)) {
            System.out.println("test5 after Instantiation");
        }
        return true;
    }

    /**
     * bean已经实例化完成，在属性注入时阶段触发，@Autowired,@Resource等注解原理基于此方法实现
     * <p>依赖注入阶段</p>
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("car".equals(beanName)) {
            System.out.println("test5 Process Properties");
        }

        return pvs;
    }


    /*--- BeanPostProcessor 的方法 ---*/
    /**
     * 执行时机： Bean 已经实例化，并且依赖注入完成。
     *
     * <p>但还没有执行 @PostConstruct、InitializingBean.afterPropertiesSet() 等初始化逻辑之前
     *
     * <p>作用： 在 Bean 初始化前做一些预处理，比如：给属性赋默认值、校验某些字段
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("car".equals(beanName)) {
            System.out.println("test5 Before Initialization");
        }

        return bean;
    }

    /**
     * 执行时机：
     * <p>Bean 完成了初始化方法（@PostConstruct、InitializingBean.afterPropertiesSet()）之后
     *
     * <p>这是 Spring AOP 的关键切入点！可以返回一个原始 Bean，也可以返回一个代理对象（例如动态代理）。
     *
     * <p>常见场景： 事务代理（@Transactional）、缓存代理（@Cacheable）、安全代理（Spring Security）
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("car".equals(beanName)) {
            System.out.println("test5 After Initialization");
        }
        return bean;
    }
}
